package part20;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.Modifier;
import com.sun.mirror.declaration.ParameterDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import part20.annotation.ExtractInterface;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author wcj
 * @Date 2021/6/6 17:47
 * @Version 1.0
 */
public class InterfaceExtractorProcessor implements AnnotationProcessor {

 private final AnnotationProcessorEnvironment env;
 private List<MethodDeclaration> interfaceMethods = new ArrayList<>();

 public InterfaceExtractorProcessor(AnnotationProcessorEnvironment env) {
  this.env = env;
 }

 @Override
 public void process() {
  for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
   ExtractInterface annotation = typeDecl.getAnnotation(ExtractInterface.class);
   if (annotation == null) {
    break;
   }
   for (MethodDeclaration method : typeDecl.getMethods()) {
    if (method.getModifiers().contains(Modifier.PUBLIC) && !method.getModifiers().contains(Modifier.STATIC)) {
     interfaceMethods.add(method);
    }
   }

   if (interfaceMethods.size() > 0) {
    try {
     PrintWriter writer = env.getFiler().createSourceFile(annotation.value());
     writer.println("package " + typeDecl.getPackage().getQualifiedName());
     writer.println("public interface " + annotation.value() + "{");
     for (MethodDeclaration m : interfaceMethods) {
      writer.print("public ");
      writer.print(m.getReturnType() + " ");
      writer.print(m.getSimpleName() + "(");
      int i = 0;
      for (ParameterDeclaration param : m.getParameters()) {
       writer.print(param.getType() + " " + param.getSimpleName());
       if (++i < m.getParameters().size()) {
        writer.print(",");
       }
      }
      writer.println(")");
     }
     writer.println("}");
     writer.close();
    } catch (IOException e) {
     throw new RuntimeException(e);
    }
   }
  }
 }
}
